# = Class ASTAssignable
# Inherits from ASTExpression. Represents the implementation of an AST especifically designed
# for assignable expressions
# == Attributes inherited from ASTExpression
# node, children
# == Methods inherited from ASTExpression
# to_s_children(im)
class ASTAssignable < ASTExpression
  # Variable that is to be assigned
  attr_reader :var
  # Access values
  attr_reader :access
  # Type of the expresion
  attr_reader :type
  # Range of the access
  attr_reader :range
  # Value returned after eval is performed
  attr_reader :value

  # Constructor of the class
  # === Parameters
  # * var: Variable that is to be assibned
  # * access: Access values
  def initialize var, access
    @var = var
    @access = access
  end

  # Method to evaluate the assignation
  # === Parameters
  # * parent_sym_table: Symbol table passed by the parent AST
  # * func_table: Function symbol table passed by the parent AST
  # === Return value
  # nil if executed with success or an error message
  def eval parent_sym_table, func_table
    if nil == @access
      return nil
    end
    if nil == parent_sym_table.find(@var.value).value
      return "Tratando de acceder a variable no inicializada '#{@var.value}' (#{@var})"
    end
    msg = @access.eval parent_sym_table, func_table
    if nil != msg
      return msg
    end
    @type = @access.type
    @range = @access.range
    @value = @access.value
    nil
  end

  # Method to check the static correctitude of the assignation
  # === Parameters
  # * parent_sym_table: Symbol table passed by the parent AST
  # * func_table: Function symbol table passed by the pare
  # * func_type: Type of valid return value
  # === Return value
  # nil if executed with success or an error message
  def check parent_sym_table, func_table, func_type
    if nil == @var || 'TkVar' != @var.class.name
      return "Error interno: ASTAssignable sin variable (#{error_location})"
    end
    sym_var = parent_sym_table.find(@var.value)
    if nil == sym_var
      return "Tratando de acceder a variable no declarada (#{error_location})"
    end

    # Validations about left operand type and access type are performed by
    
    if nil != @access
      msg = @access.check parent_sym_table, func_table, func_type
      if nil != msg
        return msg
      end
      @type = @access.type
    else
      @type = sym_var.type
    end

    nil
  end

  # Returns the closest wrong token to the place were an error is generated
  def error_tk
    tk = @var
    if nil != tk
      return tk
    end
    nil != @access ? @access.error_tk : nil
  end

  # Creates a 'String' representation of the AST with 'i' identation spaces
  # === Parameters
  # * i: Identation with which the AST should be printed with
  def to_s i
    im = i + @@c
    output = "(Variable '#{@var.value}'"
    if nil != @access
      output += " con acceso"
      output += "\n#{im}"
      output += @access.to_s im
      output += "\n#{i})"
    else
      output += ")"
    end
    output
  end
end